/**
 * Created by hwx on 2017/1/7.
 */
/*package net;

import java.util.Arrays;
import java.util.Random;*/

Arrayinit = function () {
    if (!arguments || arguments.length < 1)
        return;
    var arr = new Array(arguments[0]);
    if (arguments.length == 1) {
        for (var i = 0; i < arr.length; i++)
            arr[i] = 0;
        return arr;
    }
    arguments.__proto__ = Array.prototype;
    var nextArr = arguments.callee.apply(this, arguments.slice(1));
    console.log(arguments[0]);
    for (var j = 0; j < arguments[0]; j++) {
        arr[j] = nextArr;//new Array(j);
    }
    return arr;
};

 function BpDeep ( layernum,  rate, mobp){
 /*   this.layer;// 神经网络各层节点
 this. layerErr;// 神经网络各节点误差
    this.  layer_weight;// 各层节点权重 3维度
    this. layer_weight_delta;// 各层节点权重动量
    this.  mobp;// 动量系数
    this. rate;// 学习系数*/

     this.constru = function () {  //
         this.mobp = mobp;
         this.rate = rate;
         this.layer = new Array(layernum.length);
          this.layerErr = new Array(layernum.length);
         this.layer_weight = new Array(layernum.length - 1);//剩下2维度
         this.layer_weight_delta = new Array(layernum.length - 1);
         console.log(">>?>>构造??")
         for (var l = 0; l < layernum.length; l++) {
             // 遍历层
             this.layer[l] = new Array(layernum[l]);//new double[layernum[l]];
              this.layerErr[l] = new Array(layernum[l]);
             if (l + 1 < layernum.length) {
                 this.layer_weight[l] = Arrayinit(layernum[l] + 1, layernum[l + 1]);//  new double[layernum[l] + 1][layernum[l + 1]];  // 连接下个节点的
                 this.layer_weight_delta[l] = Arrayinit(layernum[l] + 1, layernum[l + 1]);
                 for (var j = 0; j < layernum[l] + 1; j++)
                     for (var i = 0; i < layernum[l + 1]; i++)
                         this.layer_weight[l][j][i] = Math.random();// 随机初始化权重
             }
         }
         console.log(">构造")
     };
     this.constru();
// 逐层向前计算输出
this.computeOut=function(input) { // 传数组
    for (var layIndex = 1; layIndex < this.layer.length; layIndex++) { // 遍历层
        for (var j = 0; j <  this.layer[layIndex].length; j++) {  // layIndex 每层节点j
            var prelayIndex=layIndex - 1;
            var z =this.layer_weight[prelayIndex][ this.layer[prelayIndex].length][j];  //=0; //=0; //
            //当前值 z为上一层 ,
            for (var i = 0; i <  this.layer[prelayIndex].length; i++) {  // 上一层的节点遍历
                this. layer[prelayIndex][i] = layIndex == 1 ? input[i] :  this.layer[prelayIndex][i];
                z += this.layer_weight[prelayIndex][i][j] * this. layer[prelayIndex][i];
            }
            this.layer[layIndex][j] = 1 / (1 + Math.exp(-z));
        }
    }
    return  this.layer[ this.layer.length - 1];
};

// 逐层反向计算误差并修改权重
this. updateWeight=function( tar) { // 传数组 一维度
    var layIndex = this.layer.length - 1;
    for (var j = 0; j <  this.layerErr[layIndex].length; j++)
     this.layerErr[layIndex][j] = this.layer[layIndex][j] * (1 - this.layer[layIndex][j]) * (tar[j] - this.layer[layIndex][j]);

    while (layIndex-- > 0) {
        for (var j = 0; j <  this.layerErr[layIndex].length; j++) {
            var z = 0.0;
            for (var i = 0; i <  this.layerErr[layIndex + 1].length; i++) {
                z = z + layIndex > 0 ?  this.layerErr[layIndex + 1][i] * this.layer_weight[layIndex][j][i] : 0;
                this.layer_weight_delta[layIndex][j][i] = mobp * this.layer_weight_delta[layIndex][j][i]
                    + rate *  this.layerErr[layIndex + 1][i] * this.layer[layIndex][j];// 隐含层动量调整
                this.layer_weight[layIndex][j][i] += this.layer_weight_delta[layIndex][j][i];// 隐含层权重调整
                if (j ==  this.layerErr[layIndex].length - 1) {
                    this.layer_weight_delta[layIndex][j + 1][i] = mobp * this.layer_weight_delta[layIndex][j + 1][i]
                        + rate *  this.layerErr[layIndex + 1][i];// 截距动量调整
                    this.layer_weight[layIndex][j + 1][i] += this.layer_weight_delta[layIndex][j + 1][i];// 截距权重调整
                }
            }
             this.layerErr[layIndex][j] = z * this.layer[layIndex][j] * (1 - this.layer[layIndex][j]);// 记录误差
        }
    }
};

this. train=function( input, tar) {
   var out = this.computeOut(input); // 一维的数组
    this.updateWeight(tar);
}
}
function main(){
    //初始化神经网络的基本配置
    //第一个参数是一个整型数组，表示神经网络的层数和每层节点数，比如{3,10,10,10,10,2}表示输入层是3个节点，输出层是2个节点，中间有4层隐含层，每层10个节点
    //第二个参数是学习步长，第三个参数是动量系数
    var bp = new BpDeep([2,10,2], 0.15, 0.8);
   console.log(bp);
    //设置样本数据，对应上面的4个二维坐标数据
var  data =[[1.3,1.5],[1.7,1.4],[1.4,1.2],[2.5,1.7]];
    //设置目标数据，对应4个坐标数据的分类
    var target = [[0.5,0.7],[0.5,0.5],[0.5,0.5],[0.1,0.7]];

    //迭代训练5000次
    for(var n=0;n<50000;n++)
    for(var i=0;i<data.length;i++)
    bp.train(data[i], target[i]);


    //根据训练结果来检验样本数据
    for(var j=0;j<data.length;j++){
      var  result = bp.computeOut(data[j]);
    console.log(data[j].toString()+":"+result.toString());
    }
    //根据训练结果来预测一条新数据的分类
    var x = [3,4];
    var result = bp.computeOut(x);
    console.log(x+":"+result.toString());
    console.log(JSON.stringify(bp))
}
main.bind(this)();
